/*
 * Apache trim filter
 *
 * Copyright (C) 2008 by Igor Popik <igor.popik_gmail.com> - www.thrull.com
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * $Id$
 */


/*
 * Include the core server components.
 */
#include "apr_buckets.h"
#include "apr_strings.h"
#include "ap_config.h"
#include "util_filter.h"
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_log.h"
#include "http_main.h"
#include "util_script.h"

#include "trim_processor.h"

static const char trim_filter_name[] = "TRIM";

typedef struct {
    apr_bucket_brigade *bb;
    trim_state ts;
} trim_ctx;

/*
 *      do_trim() causes two buffer copying, one done by us
 *      and the second one by apr_bucket_transient_create() - this is TODO/FIXME
 */
static apr_bucket* do_trim(const char *str, size_t len, apr_bucket_alloc_t* alloc, trim_state *ts)
{
        char *buffer;
        apr_bucket* b;
        buffer = malloc(len + 1);
        size_t out_size = 0;

        if (!buffer) {
                return NULL;
        }

        memcpy(buffer, str, len);
        out_size = trim(ts, buffer, len);
        //bucket = apr_bucket_transient_create(buffer, out_size, alloc);
        b = apr_bucket_heap_create(buffer, out_size, NULL, alloc);
        free(buffer);

        return b;
}

static apr_status_t trim_filter(ap_filter_t *f, apr_bucket_brigade *bb)
{
        apr_bucket* b;
        apr_bucket* old;
        trim_ctx *ctx = f->ctx;
        const char* buf;
        size_t bytes;

        if (!ctx) {
                f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
                apr_table_unset(f->r->headers_out, "Content-Length") ;
                apr_table_unset(f->r->headers_out, "Content-MD5") ;

                // init values
                ctx->ts.forbidden = 0;
                ctx->ts.empty = 1;
                ctx->ts.content_length = 0;
        }


        for ( b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b) ) {
                if ( APR_BUCKET_IS_EOS(b) ) {
                        //do nothing at the momment
                } else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS ) {
                        // replace old whole bucket with trimmed one
                        apr_bucket *new = do_trim(buf, bytes, f->r->connection->bucket_alloc, &ctx->ts);
                        old = b;
                        APR_BUCKET_INSERT_BEFORE(b, new);
                        apr_bucket_delete(old);
                        b = new;
                }
        }
        return ap_pass_brigade(f->next, bb);
}

/*
 * This function is a callback and it declares what
 * other functions should be called for request
 * processing and configuration requests. This
 * callback function declares the Handlers for
 * other events.
 */
static void mod_trim_register_hooks (apr_pool_t *p)
{
  ap_register_output_filter(trim_filter_name, trim_filter,
                              NULL, AP_FTYPE_RESOURCE);
}

/*
 * Declare and populate the module's data structure.  The
 * name of this structure ('tut1_module') is important - it
 * must match the name of the module.  This structure is the
 * only "glue" between the httpd core and the module.
 */
module AP_MODULE_DECLARE_DATA trim_module =
{
  // Only one callback function is provided.  Real
  // modules will need to declare callback functions for
  // server/directory configuration, configuration merging
  // and other tasks.
  STANDARD20_MODULE_STUFF,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  mod_trim_register_hooks,      /* callback for registering hooks */
};


